﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Management.Instrumentation;
using System.Text;
using System.Diagnostics;
using System.IO;
using System.Windows.Forms;
using System.Threading;
using System.Text.RegularExpressions;
using Framework;

namespace Framework.Logic.Server
{
    public class MCServer : IMCServer
    {
        public bool IsRunning { get; private set; }

        public event EventHandler NewOutputLine;
        public event EventHandler NewErrorLine;

        public void Stop()
        {
            Send("stop server");
            IsRunning = false;
        }

        public void Send(string strCommand)
        {
            inputWriter.Write(strCommand + "\n");
            inputWriter.Flush();
        }

        public void KillProcess()
        {
            if (plinkProcess != null)
            {
                plinkProcess.Kill();
            }
        }


        private Process plinkProcess { get; set; }

        private string CalculateRamInMB()
        {
            if (config.Default.AllocatedRAM == null || !config.Default.AllocatedRAM.Contains("GB"))
                return "1024M";

            string strRAM = config.Default.AllocatedRAM;
            if (!strRAM.Contains("."))
            {
                return strRAM.Replace("B","");
            }

            double dbRamGB = Convert.ToDouble(Regex.Replace(strRAM, "[^0-9.]", ""));

            double dbRamMB = dbRamGB * 1024.0;

            return dbRamMB.ToString() + "M";
        }

        public void Start(string FilePath)
        {
            try
            {
            IsRunning = true;
            string memoryArgument = String.Format("-Xms{0} -Xmx{0}",CalculateRamInMB()); 
            string filePathArgument = String.Format(" -jar {0} -nojline",FilePath);
            ProcessStartInfo psi = new ProcessStartInfo("java", memoryArgument +  filePathArgument);
            psi.UseShellExecute = false;
            psi.ErrorDialog = false;
            psi.WorkingDirectory = Path.GetDirectoryName(FilePath);
            psi.CreateNoWindow = true;
            psi.WindowStyle = ProcessWindowStyle.Hidden;
            psi.RedirectStandardInput = true;
            psi.RedirectStandardError = true;
            plinkProcess = new Process();
            plinkProcess.StartInfo = psi;
            plinkProcess.Start();
            inputWriter = plinkProcess.StandardInput;
            outputReader = plinkProcess.StandardError; //MC command line text comes out as errors not standard output? weird.
            inputWriter.AutoFlush = false;
            }
            catch (InstanceNotFoundException ex)
            {
                throw;
            }

            Thread thread = new Thread(MonitorOutput);
            thread.Start();
        }

        public List<string> outputStrings { get; set; }
        public List<string> Output { get { return outputStrings; } set { outputStrings = value; } }


        private void MonitorOutput()
        {
            Output = new List<string>();
            while (true)
            {
                var outputLine = outputReader.ReadLine();
                if (outputLine == null || string.IsNullOrWhiteSpace(outputLine))
                    return;

                if (outputLine.Contains("[INFO] Done"))
                {
                   
                }

                Output.Add(outputLine);
                if (this.NewOutputLine != null)
                {
                    this.NewOutputLine(outputLine, new EventArgs());
                }
                if (this.NewErrorLine != null)
                {
                    if (outputLine.Contains("Could not create the Java virtual machine"))
                    {
                        this.NewErrorLine("Please reduce the allocated RAM to 1GB or install a 64bit OS with 64bit Java installed.", new EventArgs());
                    }
                }
            }
        }

       public StreamWriter inputWriter
        {
            get;
            set;
        }

       public StreamReader outputReader
        {
            get;
            set;
        }
    }
}
